package com.winiex.datastructure;

import java.util.ArrayList;

import com.winiex.datastructure.exception.QueueEmptyException;
import com.winiex.datastructure.exception.SqQueueFullException;

public class SqQueue<T> implements Queue<T> {

	private ArrayList<T> data = null;

	private int front;
	private int rear;

	private int size;

	/**
	 * Initialize a SqQueue with a size dataNum specifies.
	 * 
	 * @param dataNum
	 *            the SqQueue size.
	 */
	public SqQueue(int dataNum) {
		data = new ArrayList<T>(dataNum);
		for (int i = 0 ; i < dataNum ; i++) {
			data.add(null);
		}
		this.front = 0;
		this.rear = 0;
		this.size = dataNum;
	}

	/**
	 * Initialize a SqQueue with size 5.
	 */
	public SqQueue() {
		this(5);
	}

	@Override
	public void ClearQueue() {
		data.clear();
		front = 0;
		rear = 0;
		size = 0;
	}

	@Override
	public boolean QueueEmpty() {
		boolean isEmpty = false;

		if (front == rear) {
			isEmpty = true;
		}

		return isEmpty;
	}

	@Override
	public int QueueLength() {
		return (rear - front) % size;
	}

	@Override
	public T GetHead() {
		return data.get(front);
	}

	@Override
	public void EnQueue(T node) throws SqQueueFullException {
		// if the queue is full, then throw a exception.
		if ((rear + 1) % size == front) {
			throw new SqQueueFullException("The Queue is full.Can't EnQueue.");
		}
		
		data.set(rear, node);
		rear = (rear + 1) % size;
	}

	@Override
	public T DeQueue() throws QueueEmptyException {
		// if the queue is empty, then throw a exceptoin.
		if (rear == front) {
			throw new QueueEmptyException("The Queue is empty.Can't DeQueue.");
		}
		
		try {
			return data.get(front);
		} finally {
			front = (front + 1) % size;
		}
	}

	@Override
	public void QueueTraverse(Traverse<T> t) {
		/*int counter = front;
		for (; counter % size <= rear ; counter ++) {
			t.traverse(data.get(counter));
		}*/
		if (front == rear) {
			return;
		} else if (front < rear) {
			for (int counter = front ; counter < rear ; counter++) {
				t.traverse(data.get(counter));
			}
		} else {
			for (int counter = front ; counter < size ; counter++) {
				t.traverse(data.get(counter));
			}
			for (int counter = 0 ; counter < rear ; counter++) {
				t.traverse(data.get(counter));
			}
		}
	}
	
	public static class DefaultSqQueueTraverse<T> implements Traverse<T> {

		@Override
		public void traverse(T t) {
			System.out.println(t.toString());
		}
		
	}
}
